/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-07-31     Administrator       the first version
 */


#include "bsp_pin_cfg.h"
#include <rtthread.h>
#include <rtdevice.h>
#include "hal_data.h"
#include "multi_button.h"
#include "lcd1602.h"
#include "drv_common.h"


#define FUNC_LINE_CHANGE(y)         (!!y)
#define FUNC_ROW_CHANGE(x)          (0x0F & x)

#define LCD1602_FIRST_LINE          (0)
#define LCD1602_SENCOND_LINE        (1)

#define LCD1602_TYPE_COM            (0)
#define LCD1602_TYPE_DAT            (1)

static int lcd1602_init(void);
static void lcd1602_transfer_byte(unsigned char dat, unsigned char type);
static void lcd1602_set_cursor(unsigned char x, unsigned char y);

static int lcd1602_init(void)
{
    lcd1602_write_com(0x38);
    lcd1602_write_com(0x0c);
    lcd1602_write_com(0x06);
    lcd1602_write_com(0x01);

    return RT_EOK;
}
INIT_PREV_EXPORT(lcd1602_init);

void lcd1602_write_com(unsigned char com)
{
    lcd1602_transfer_byte(com, LCD1602_TYPE_COM);
}

void lcd1602_write_byte(unsigned char x, unsigned char y, unsigned char dat)
{
    lcd1602_set_cursor(x, y);

    lcd1602_transfer_byte(dat, LCD1602_TYPE_DAT);
}

void lcd1602_write_str(unsigned char x, unsigned char y, unsigned char * str)
{
    lcd1602_set_cursor(x, y);

    while(*str != '\0')
    {
        lcd1602_transfer_byte(*str++, LCD1602_TYPE_DAT);
    }
}

static void lcd1602_set_cursor(unsigned char x, unsigned char y)
{
    unsigned char addr;

    y = FUNC_LINE_CHANGE(y);
    x = FUNC_ROW_CHANGE(x);

    if(y == LCD1602_FIRST_LINE)
    {
        addr = 0x80 + x;
    }
    else
    {
        addr = 0x80 + 0x40 + x;
    }

    lcd1602_write_com(addr);
}

static void lcd1602_transfer_byte(unsigned char dat, unsigned char type)
{
    if(type == LCD1602_TYPE_COM)
    {
        rt_pin_write(LCD1602_EN, PIN_LOW);
        rt_pin_write(LCD1602_RS, PIN_LOW);
        rt_pin_write(LCD1602_RW, PIN_LOW);
    }
    else
    {
        rt_pin_write(LCD1602_EN, PIN_LOW);
        rt_pin_write(LCD1602_RS, PIN_HIGH);
        rt_pin_write(LCD1602_RW, PIN_LOW);
    }

    rt_pin_write(LCD1602_DATA0, ((dat & 0x01) >> 0));
    rt_pin_write(LCD1602_DATA1, ((dat & 0x02) >> 1));
    rt_pin_write(LCD1602_DATA2, ((dat & 0x04) >> 2));
    rt_pin_write(LCD1602_DATA3, ((dat & 0x08) >> 3));
    rt_pin_write(LCD1602_DATA4, ((dat & 0x10) >> 4));
    rt_pin_write(LCD1602_DATA5, ((dat & 0x20) >> 5));
    rt_pin_write(LCD1602_DATA6, ((dat & 0x40) >> 6));
    rt_pin_write(LCD1602_DATA7, ((dat & 0x80) >> 7));

    rt_pin_write(LCD1602_EN, PIN_HIGH);
    rt_thread_mdelay(5);
    rt_pin_write(LCD1602_EN, PIN_LOW);
}
